/********************************************************************/
/*																	*/
/*  IconButton.cpp													*/
/*																	*/
/*  Implementation of the CIconButton.								*/
/*																	*/
/*	This class make it possible to display an icon and text on a	*/
/*	button, which unfortunately can't be done with CButton...		*/
/*																	*/
/*  Programmed by Pablo van der Meer								*/
/*  Copyright Pablo Software Solutions 2005							*/
/*	http://www.pablosoftwaresolutions.com							*/
/*																	*/
/*  Last updated: May 28, 2005										*/
/*																	*/
/********************************************************************/

#include "stdafx.h"
#include "IconButton.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


CIconButton::CIconButton()
{
	m_hIcon = NULL;
}

CIconButton::~CIconButton()
{
	if(m_hIcon != NULL)
		DeleteObject(m_hIcon);
}


BEGIN_MESSAGE_MAP(CIconButton, CButton)
	//{{AFX_MSG_MAP(CIconButton)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/********************************************************************/
/*																	*/
/* Function name : DrawItem											*/
/* Description   : Called by the framework when a visual aspect of	*/
/*				   an owner-draw button changes.					*/
/*																	*/
/********************************************************************/
void CIconButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	
	UINT uStyle = DFCS_BUTTONPUSH;

	// if button is pushed, add the pushed style to DrawFrameControl
	if (lpDrawItemStruct->itemState & ODS_SELECTED)
		uStyle |= DFCS_PUSHED;

	// is button flat ?
	if (GetStyle() & BS_FLAT)
		uStyle |= DFCS_FLAT;

	// clear background
	pDC->FillSolidRect(&lpDrawItemStruct->rcItem, ::GetSysColor(COLOR_BTNFACE));

	// draw the button frame
	::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, DFC_BUTTON, uStyle);

	// get button text
	CString strText;
	GetWindowText(strText);

	// set default button colors
	pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT));
	pDC->SetBkColor(::GetSysColor(COLOR_BTNFACE));
	pDC->SetBkMode(TRANSPARENT);

	// is button disabled ?
	BOOL bDisabled = (lpDrawItemStruct->itemState & ODS_DISABLED);

	CRect rcIcon(0,0,0,0);
	// icon loaded ?
	if(m_hIcon)
	{
		// calculate icon's rectangle
		rcIcon = lpDrawItemStruct->rcItem;
		CalcIconRect(pDC, rcIcon);

		CPoint pt = rcIcon.TopLeft();

		if (lpDrawItemStruct->itemState & ODS_SELECTED)
			pt.Offset(1, 1);

		// draw icon
		pDC->DrawState(pt, CSize(m_nIconWidth, m_nIconHeight), (HICON)m_hIcon, DST_ICON | (bDisabled ? DSS_DISABLED : DSS_NORMAL), (CBrush *)NULL);
	}
	else
	{
		// if no icon is loaded, just display text
	}

	// calculate text's rectangle
	CRect rcText = lpDrawItemStruct->rcItem;
	CalcTextRect(pDC, strText, rcText, rcIcon);

	if (lpDrawItemStruct->itemState & ODS_SELECTED)
		rcText.OffsetRect(1, 1);

	// draw text
	pDC->DrawState(rcText.TopLeft(), rcText.Size(), (LPCTSTR)strText, (bDisabled ? DSS_DISABLED : DSS_NORMAL), TRUE, 0, (CBrush*)NULL);

	// and finally draw the focus rectangle
	if(lpDrawItemStruct->itemState & ODS_FOCUS)
	{
		rcText = lpDrawItemStruct->rcItem;
		::InflateRect(&rcText, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE));
		pDC->DrawFocusRect(&rcText);
	}
}


/********************************************************************/
/*																	*/
/* Function name : PreSubclassWindow								*/
/* Description   : Initialize some stuff							*/
/*																	*/
/********************************************************************/
void CIconButton::PreSubclassWindow() 
{
	// set default style
	ModifyStyle(NULL, BS_OWNERDRAW | BS_ICON | BS_VCENTER | BS_LEFT);
	CButton::PreSubclassWindow();
}


/********************************************************************/
/*																	*/
/* Function name : SetIcon											*/
/* Description   : Set button's icon								*/
/*																	*/
/********************************************************************/
BOOL CIconButton::SetIcon(UINT nID, int nWidth, int nHeight)
{
	HINSTANCE hInstance = AfxFindResourceHandle(MAKEINTRESOURCE(nID), RT_GROUP_ICON);
	m_hIcon = (HICON)::LoadImage(hInstance, MAKEINTRESOURCE(nID), IMAGE_ICON, nWidth, nHeight, 0);

	if (m_hIcon == NULL)
		return FALSE;

	m_nIconWidth = nWidth;
	m_nIconHeight = nHeight;
	return TRUE;
}


/********************************************************************/
/*																	*/
/* Function name : CalcIconRect										*/
/* Description   : Calculate icon's rectangle depending on button	*/
/*				   style.											*/
/*																	*/
/********************************************************************/
BOOL CIconButton::CalcIconRect(CDC *pDC, CRect &rcIcon)
{
	DWORD dwStyle = GetStyle();
	CRect rc = rcIcon;

	// calculate icon rectangle 
	rc.right  = rc.left + m_nIconWidth;
	rc.bottom = rc.top  + m_nIconHeight;

	int nOffset;
	switch(dwStyle & (BS_CENTER|BS_RIGHT))
	{
		case BS_LEFT:    
			rc.left += 4;  
			rc.right += 4;  
			break;

		case BS_CENTER:  
			nOffset = rc.right - rc.left;
            rc.left = rcIcon.left + ((rcIcon.right - rcIcon.left) - nOffset) / 2;
            rc.right = rc.left + nOffset; 
			break;
		
		case BS_RIGHT:   
			nOffset = rc.right - rc.left;
            rc.right = rcIcon.right - 4;
            rc.left = rc.right - nOffset;
            break;
	}

   	switch (dwStyle & (BS_VCENTER|BS_BOTTOM))
	{
		case BS_TOP:     
			rc.top += 3;  
			rc.bottom += 3;  
			break;
		
		case BS_VCENTER: 
			nOffset = rc.bottom - rc.top;
            rc.top = rcIcon.top + ((rcIcon.bottom - rcIcon.top) - nOffset) / 2;
            rc.bottom = rc.top + nOffset;
			break;
		
		case BS_BOTTOM:  
			nOffset = rc.bottom - rc.top;
            rc.bottom = rcIcon.bottom - 3;
            rc.top = rc.bottom - nOffset;
            break;
	}
	rcIcon = rc;
	return TRUE;
}


/********************************************************************/
/*																	*/
/* Function name : CalcTextRect										*/
/* Description   : Calculate text's rectangle depending on button	*/
/*				   style.											*/
/*																	*/
/********************************************************************/
BOOL CIconButton::CalcTextRect(CDC *pDC, LPCTSTR lpszText, CRect &rcText, CRect &rcIcon)
{
	DWORD dwStyle = GetStyle();

	CRect rc = rcText;

	switch(dwStyle & (BS_CENTER|BS_RIGHT))
	{
		case BS_LEFT:    
			rc.left = rcIcon.right;  
			break;

		case BS_CENTER:  
			rc.top = rcIcon.bottom;
			break;
		
		case BS_RIGHT:   
			rc.right = rcIcon.left;
            break;
	}

	rcText = rc;

	// calculate text size	
	pDC->DrawText(lpszText, -1, &rc, DT_SINGLELINE | DT_CALCRECT);

   	switch (dwStyle & (BS_VCENTER|BS_BOTTOM))
	{
		case BS_TOP:     
			rc.OffsetRect((rcText.Width() - rc.Width())/2, rcIcon.top + rcIcon.Height()/2 - rc.Height()/2);
			break;
		
		case BS_VCENTER: 
			rc.OffsetRect((rcText.Width() - rc.Width())/2, (rcText.Height() - rc.Height())/2);
			rc.OffsetRect(0, -1);
			break;
		
		case BS_BOTTOM:  
			rc.OffsetRect((rcText.Width() - rc.Width())/2, rcIcon.top + rcIcon.Height()/2 - rc.Height()/2);
			break;
	}

	rcText = rc;
	return TRUE;
}



